/* 
 * File:   AnimationLogic.cpp
 * Author: RedEyedKiller
 * 
 * Created on 21 Απρίλιος 2011, 12:58 μμ
 */

#include "AnimationLogic.h"
#include "Logger.h"
#include "sdl/GraphicsCore.h"

#define FirstFrame 0

namespace EntitySystem
{

AnimationLogic::AnimationLogic()
{
    currentAnimation = defaultAnimation;
    currentFrame = FirstFrame;
}

AnimationLogic::AnimationLogic(const AnimationLogic& orig) : DrawLogic(orig)
{
    this->currentAnimation = orig.currentAnimation;
    this->defaultAnimation = orig.defaultAnimation;
    this->currentFrame = orig.currentFrame;
    this->playing = orig.playing;
    this->afterEnd = orig.afterEnd;
    AnimationTable::const_iterator it = orig.animationMap.begin();
    AnimationTable::const_iterator end = orig.animationMap.end();
    for(; it != end; ++it )
    {
        this->animationMap[it->first] = it->second;
    }
}

AnimationLogic::~AnimationLogic()
{
}

AnimationLogic* AnimationLogic::Clone()
{
    return new AnimationLogic(*this);
}

void AnimationLogic::Draw(sdl::GraphicsCore *gCore, Camera *camera)
{
    //get current animation frame
    int frameNumber;
    AnimationFrame cFrame = animationMap[currentAnimation];
    //update animation
    Update(cFrame, &frameNumber);

    ////draw 
    const gl::Texture* texture = m_display->GetRawData();
    if( texture == NULL )
    {
        LOG(Logger::CHANNEL_GRAPHICS, LogFileStream::LEVEL_ERROR) << "Animation logic failed to draw. Image is NULL.";
		return;
    }
    Math::Rect firstFrame = cFrame.firstFrame;
    //create the clip of the image
    Math::Rect clip(
                    firstFrame.GetTop(), 
                    firstFrame.GetLeft() + firstFrame.GetWidth() * ( frameNumber ),
                    firstFrame.GetHeight(),
                    firstFrame.GetWidth()
                    );
    //actual draw 
    gCore->Render(*texture, clip, m_color,
                  Math::Vector2F(GetX() - camera->GetRect()->GetLeft(), GetY() - camera->GetRect()->GetTop()), m_scale,m_angle,cFrame.flip,m_blending);
}

void AnimationLogic::Update(AnimationFrame& frame, int* frameNumber)
{
    *frameNumber = currentFrame;
    //if playing is false it means that there should be no animation
    if( !playing )
        return;
    //check if enough time has passed since the last update
    if( timer.Update(frame.totalTime) )
    {
        //add one to current frame and check if it has surpassed the limit
        if( ++currentFrame >= frame.numberOfFrames )
        {
            //if animation is one time play stop it
            if( afterEnd == ANIM_ONESHOT )
            {
                playing = false;
            }
            else if( afterEnd == ANIM_TODEFAULT )//return to default
            {
                currentAnimation = defaultAnimation;
                //and reset the counter
                currentFrame = FirstFrame;
                //frame = animationMap[currentAnimation];
            }
            else/*afterEnd == ANIM_LOOPING*/
            {
                currentFrame = FirstFrame;
            }
        }
    }

}

void AnimationLogic::Play(const std::string& animation, AfterEnd afterEnd)
{
    if( animation == currentAnimation )
    {
        this->afterEnd = afterEnd;
        return;
    }

    if( animationMap.find(animation) != animationMap.end() )
    {
        currentAnimation = animation;
        this->afterEnd = afterEnd;
        playing = true;
        //reset frame counter
        currentFrame = FirstFrame;
        //...and timer
        timer.Reset();
    }
    else
    {
        currentAnimation = defaultAnimation;
        LOG(Logger::CHANNEL_GRAPHICS, LogFileStream::LEVEL_ERROR) << "Animation logic failed to play animation. "
                "Such animation name (" << animation << ") does not exist.";
    }
}

void AnimationLogic::Pause()
{
    timer.Reset();
    this->playing = false;
}

void AnimationLogic::Resume()
{
    playing = true;
}

void AnimationLogic::AddFrame(const std::string& name, const AnimationFrame& frame)
{
    animationMap[name] = frame;
}

bool AnimationLogic::GetFrame(const std::string& name,AnimationFrame& frame)
{
    if( animationMap.find(name) != animationMap.end() )
    {
        frame = animationMap[name];
        return true;
    }
    return false;
}

void AnimationLogic::SetPlaying(bool playing)
{
    this->playing = playing;
}

void AnimationLogic::SetCurrentFrame(int currentFrame)
{
    this->currentFrame = currentFrame;
}

void AnimationLogic::SetCurrentAnimation(const std::string &currentAnimation)
{
    this->currentAnimation = currentAnimation;
}

std::string AnimationLogic::GetCurrentAnimation() const
{
    return currentAnimation;
}

void AnimationLogic::SetDefaultAnimation(const std::string &defaultAnimation)
{
    this->defaultAnimation = defaultAnimation;
}

/**
 * Overrides Draw Logic's GetWidth in order to supply valid image width.
 *
 * @return current frame's width.
 */

int AnimationLogic::GetWidth() const
{
    //find current animation
    std::map< std::string, AnimationFrame >::const_iterator currAnimation(animationMap.find(currentAnimation));

    return(currAnimation != animationMap.end() ) ? currAnimation->second.firstFrame.GetWidth() : 0;
}

/**
 * Overrides Draw Logic's GetHeight in order to supply valid image height.
 *
 * @return current frame's height.
 */

int AnimationLogic::GetHeight() const
{
    //find current animation
    std::map< std::string, AnimationFrame >::const_iterator currAnimation(animationMap.find(currentAnimation));

    return(currAnimation != animationMap.end() ) ? currAnimation->second.firstFrame.GetHeight() : 0;
}

}